class Context {
    constructor(input) {
        this.input = input
        this.output = 0
    }
}

class Expression {
    interpreter (context) {
        throw new Error("抽象方法未实现")
    }
}

class ThousandExpression extends Expression {
    interpreter (context) {
        const str = context.input
        if (str.startsWith("M")) {
            context.output += 1000
            context.input = str.slice(1)
        }
    }
}

class HundredExpression extends Expression {
    interpreter (context) {
        let has = true
        while (has) {
            const str = context.input
            if (str.startsWith('CD')) {
                context.output += 400
                context.input = str.slice(2)
                continue
            } else if (str.startsWith("CM")) {
                context.output += 900
                context.input = str.slice(2)
                continue
            } else if (str.startsWith('C')) {
                context.output += 100
                context.input = str.slice(1)
                continue
            }
            has = false
        }
    }
}

class TenExpression extends Expression {
    interpreter (context) {
        let has = true
        while (has) {
            const str = context.input
            if (str.startsWith('XC')) {
                context.output += 90
                context.input = str.slice(2)
                continue
            } else if (str.startsWith('XL')) {
                context.output += 40
                context.input = str.slice(2)
                continue
            } else if (str.startsWith('X')) {
                context.output += 10
                context.input = str.slice(1)
                continue
            }
            has = false
        }
    }
}

class OneExpression extends Expression {
    interpreter (context) {
        let has = true
        while (has) {
            const str = context.input
            if (str.startsWith('IX')) {
                context.output += 9
                context.input = str.slice(2)
                continue
            } else if (str.startsWith('IV')) {
                context.output += 4
                context.input = str.slice(2)
                continue
            } else if (str.startsWith('V')) {
                context.output += 5
                context.input = str.slice(1)
                continue
            } else if (str.startsWith('I')) {
                context.output += 1
                context.input = str.slice(1)
                continue
            }
            has = false
        }
    }
}

class Interpreter {
    static parse (roman) {
        const context = new Context(roman)
        const tree = [
            new ThousandExpression(),
            new HundredExpression(),
            new TenExpression(),
            new OneExpression(),
        ]
        tree.forEach((expression) => expression.interpreter(context))
        return context.output
    }
}

console.log(Interpreter.parse('CDXLVIII'))